/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package rs_GUI;

import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import pojos.*;
import java.util.List; 
import java.util.Objects;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.swing.JOptionPane;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
 *
 * @author KATERINA
 */
public class XmlManagement {
    //Πεδία
    private EntityManager em;
    private Playlist pl;
    private DateFormat df;
    private String fname;
    private String xmlName;
    private String fileName;
    private File f;
    private Playlist pl2;
    

    //Ο constractor
    public XmlManagement(EntityManager em) {
        this.em = em;
        df = new SimpleDateFormat("dd/MM/yyyy");
    }
    
    //Λοιπές μέθοδοι
    public void createXml(Playlist pl, String fname, String fileName, String xmlName){
        this.fname = fname;
        this.pl = pl;
        this.fileName = fileName;
        this.xmlName = xmlName;
        try{
            // Δημιουργώ ένα καινούργιο αρχείο
            // Δημιουργία parser που παράγει το DOM XML αρχείων
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); 

            //Δυνατότητα δημιουργίας των στιγμιότυπων του XML αρχείου από το DOM
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); 

            // αναφέρεται στο XML αρχείο, είναι η ιδεατή ρίζα του δέντρου
            Document doc = docBuilder.newDocument();
            
            //................//
            // δημιουργώ την ρίζα Playlist
            Element rootElement = doc.createElement("playlist"); // δημιουργία tag Playlist
            doc.appendChild(rootElement); // προσθήκη tag ως παιδί του κόμβου rootElement
            
            // δημιουργώ το όνομα της λίστας
            Element name = doc.createElement("name"); // δημιουργία tag name
            name.appendChild(doc.createTextNode(pl.getName())); // προσθήκη του ονόματος της λίστας
            rootElement.appendChild(name); // το θέτουμε ως παιδί του rootElement
            
            // δημιουργώ την ημερομηνία δημιουργίας της λίστας
            Element date = doc.createElement("creationDate"); // δημιουργία tag creationDate
            date.appendChild(doc.createTextNode(df.format(pl.getCreation()))); // προσθήκη του την ημερομηνίας δημιουργίας της λίστας
            rootElement.appendChild(date); // το θέτουμε ως παιδί του rootElement
            
            // δημιουργώ τη λίστα τραγουδιών της λίστας
            Element songs = doc.createElement("songs"); // δημιουργία tag songs
            rootElement.appendChild(songs); // το θέτουμε ως παιδί του rootElement
            for(Song s : pl.getSongList()){
                Element song = doc.createElement("song"); // δημιουργία tag song
                songs.appendChild(song); // το θέτουμε ως παιδί του songs
                
                Element id = doc.createElement("id"); // δημιουργία tag id
                id.appendChild(doc.createTextNode(""+s.getId())); // προσθήκη του id του τραγουδιού
                song.appendChild(id); // το θέτουμε ως παιδί του song
                
                Element title = doc.createElement("title"); // δημιουργία tag title
                title.appendChild(doc.createTextNode(s.getTitle())); // προσθήκη του τίτλου του τραγουδιού
                song.appendChild(title); // το θέτουμε ως παιδί του song
                
                Element duration = doc.createElement("duration"); // δημιουργία tag duration
                duration.appendChild(doc.createTextNode(""+s.getDuration())); // προσθήκη του duration του τραγουδιού
                song.appendChild(duration); // το θέτουμε ως παιδί του song
            }
            
            // γράφω όλα τα παραπάνω σε ένα αρχείο xml
            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            DOMSource source = new DOMSource(doc);
            StreamResult result;
            //δημιουργώ το αρχείο xml
            result = new StreamResult(new File(""+fileName+"\\"+xmlName+".xml"));
            transformer.transform(source, result);
            
            JOptionPane.showMessageDialog(null, "Το αρχείο\n"+xmlName+".xml\n"
                    + "αποθηκεύτηκε με επιτυχία!"
                    + "\n"
                    + "\nΔιαδρομή αρχείου:\n"+fileName+"\\"+xmlName+".xml\"", 
                                           "",
                                           JOptionPane.INFORMATION_MESSAGE);
            
        }
        catch (ParserConfigurationException pce) {
            pce.printStackTrace();
        }
        catch (TransformerException tfe) {
            tfe.printStackTrace();
        }
    }
    
    public Playlist readXml(File f, String xmlName) {
        this.f = f;
        this.xmlName = xmlName;
        try {

            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            Document doc = builder.parse(f);
            
            //Ανακτώ τα περιεχόμενα του xml
            String nNode = doc.getElementsByTagName("name").item(0).getTextContent(); //Το όνομα της λίστας
            String dNode = doc.getElementsByTagName("creationDate").item(0).getTextContent(); //H ημερομηνία δημιουργίας
            
            //Φτιάχνω μία νέα playlist
            pl2 = new Playlist(null);
            //Βάζω τo μέχρι τώρα ανακτημένο περιεχόμενο σε μία νέα playlist
            pl2.setCreation(df.parse(dNode));
            
            
            //Νέα δοσοληψία
            if (!em.getTransaction().isActive()) {
                em.getTransaction().begin();
            }
            //................................................................//
            //             Ψάχνουμε να δούμε αν υπάρχει ήδη                   //
            //             λίστα με αυτό το όνομα στη ΒΔ μας                  //
            //................................................................//
            //Δημιουργία Query που φέρνει όλες τις λίστες της ΒΔ
            TypedQuery<Playlist> q1 = em.createNamedQuery("Playlist.findAll", Playlist.class);
            List<Playlist> plList= new ArrayList<>();
            plList.addAll(q1.getResultList());
            
            //Ελέγχω ένα ένα τα ονόματα των λιστών της ΒΔ
            //και τα συγκρίνω με αυτό του αρχείου xml
            for(Playlist p : plList){
                if(p.getName().equals(nNode)){
                    JOptionPane.showMessageDialog(null, "Υπάρχει λίστα με το όνομα:"
                        + "\n"+nNode+"\nστη Βάση Δεδομένων."
                        + "\nΗ λίστα δεν μπορεί να εισαχθεί.",
                             "Σφάλμα",
                        JOptionPane.WARNING_MESSAGE);
                    //Κλείνουμε τη δοσοληψία
                    em.getTransaction().commit();
                    return null;
                }
            }
            pl2.setName(nNode);
             
            //Κάνω persist την pl στη ΒΔ   
            em.persist(pl2);
            //Ρίχτη στη ΒΔ
            em.flush();
            
            
            //................................................................//
            //             Ψάχνουμε να δούμε αν όλα τα τραγούδια              //
            //             της νέας λίστας υπάρχουν στη ΒΔ μας                //
            //................................................................//
          
            //Δημιουργία Query που φέρνει όλα τα τραγούδια της ΒΔ
            TypedQuery<Song> q = em.createNamedQuery("Song.findAll", Song.class);
            List<Song> songList= new ArrayList<>();
            songList.addAll(q.getResultList());
           
            //Βρίσκω πόσα τραγούδια περιέχει η λίστα τραγουδιών του xml
            //και τα βάζω σε μία λίστα.
            NodeList sList = doc.getElementsByTagName("song");
            int sNodeListSize = sList.getLength();
            //Ανακτώ ένα ένα τα τραγούδια
            for(int i = 0; i < sNodeListSize; i++){
                boolean songFound = false;
                //Ανάκτηση τραγουδιού
                Node sNode = sList.item(i);
                //Ανάκτηση των στοιχείων του
                Node sIdNode = sNode.getFirstChild(); //Το id
                String sTitle = sNode.getFirstChild().getNextSibling().getTextContent();
                //Μετατροπή του sIdNode σε Integer 
                Integer sId = Integer.parseInt(sIdNode.getTextContent());
                
                for(Song s1 : songList){
                    if((Objects.equals(s1.getId(), sId)) && (s1.getTitle().equals(sTitle))){
                        songFound = true;
                    }
                }
                if(songFound){
                    TypedQuery<Song> q2 = em.createNamedQuery("Song.findById", Song.class);
                    q2.setParameter("id", sId);
                    Song x = q2.getSingleResult();
                    pl2.getSongList().add(x);
                }
                else{
                    JOptionPane.showMessageDialog(null, "Το αρχείο:\n"+xmlName+"\n"
                        + "περιέχει τραγούδια"
                        + "\nπου δεν υπάρχουν στη Βάση Δεδομένων."
                        + "\n\nΗ λίστα δεν μπορεί να εισαχθεί.\n   ",
                             "Σφάλμα",
                        JOptionPane.WARNING_MESSAGE);
                    em.remove(pl2);
                    //Κλείνουμε τη δοσοληψία
                    em.getTransaction().commit();
                    return null;
                } 
            }
            //Κλείνουμε τη δοσοληψία
            em.getTransaction().commit();
            JOptionPane.showMessageDialog(null, "Η εισαγωγή της λίστας\n"
                    + "ήταν επιτυχής!", 
                    "",
                    JOptionPane.INFORMATION_MESSAGE);
        }
        catch (FactoryConfigurationError fce){
            JOptionPane.showMessageDialog(null, "Could not create DocumentBuilderFactory.",
                             "Σφάλμα",
                        JOptionPane.WARNING_MESSAGE);
        }
        catch (ParserConfigurationException pce) {
            JOptionPane.showMessageDialog(null, "Could not locate a JAXP parser.",
                             "Σφάλμα",
                        JOptionPane.WARNING_MESSAGE); 
        }
        catch (SAXException se) {
            JOptionPane.showMessageDialog(null, "XML file is not well-formed.",
                             "Σφάλμα",
                        JOptionPane.WARNING_MESSAGE); 
        }
        catch (IOException ioe) { 
            JOptionPane.showMessageDialog(null, "Due to an IOException,\n"
                    + "the parser could not read the XML file.",
                             "Σφάλμα",
                        JOptionPane.WARNING_MESSAGE);
        }
        catch (ParseException pe) { 
            JOptionPane.showMessageDialog(null, "Due to an ParseException,\n"
                    + "the parser could not read the XML file.",
                             "Σφάλμα",
                        JOptionPane.WARNING_MESSAGE);
        }
        catch(Exception ex) { 
            JOptionPane.showMessageDialog(null, "Προσπαθείτε να εισάγεται ένα\n"
                    + "μη σωστά μορφοποιημένο xml", "Σφάλμα",
                    JOptionPane.WARNING_MESSAGE);
        }
        return pl2;
    }
}
